#include <algorithm>
#include <cmath>
#include <mpi.h>
#include "jacobi.hh"
#include "../utils/tools.hh"
#include "../utils/solver.hh"

void icehpc::jacobi(hexagon const& hex, solver & s)
{
    auto size = MPI::COMM_WORLD.Get_size();
    auto rank = MPI::COMM_WORLD.Get_rank();

    auto start = tools::start_id(hex.n, size, rank);
    auto end   = tools::  end_id(hex.n, size, rank);

    auto& au      = s.au;
    auto& u       = s.u;
    auto& b       = s.b;
    auto& max_error = s.max_error;
    max_error       = 0;

    // 遍历每个进程所维护的点
    for (auto id = start, i = 0; id <= end; id++, i++) {
        if (id == hex.except_id || hex.outside(id)) continue;;

        // 得到它上下左右的 id
        auto up    = hex.   up(id);
        auto down  = hex. down(id);
        auto left  = hex. left(id);
        auto right = hex.right(id);

        // 根据报告中的关系进行迭代
        if (hex.top(id)) {
            u[i] = (b[i] + 3 * au[right] + 3 * au[left] + 2 * au[down]) / 8.;
        } else if (hex.bottom(id)) {
            u[i] = (b[i] + 3 * au[right] + 3 * au[left] + 2 * au[up]) / 8.;
        } else if (hex.boundary(id)) {
            auto id1 = hex.x_non_empty_dir(id);
            auto id2 = hex.y_non_empty_dir(id);
            u[i] = (b[i] + 6 * au[id1] + 2 * au[id2]) / 8.;
        } else if (hex.inside(id)) {
            u[i] = (b[i] + 3 * au[left] + 3 * au[right] + au[up] + au[down]) / 8.;
        }

        auto tmp_error = tools::abs(u[i] - au[tools::identity(hex.n, i, size, rank)]);
        // tmp_error /= u[i];
        // 统计这些点的最大误差
        max_error = std::max(max_error, tmp_error);
    }
}

